home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Toolbox / Tabs LDEF 1.0 / Documentation / ReadMe- Tabs LDEF next >
Encoding:
Text File  |  1996-01-16  |  14.6 KB  |  208 lines  |  [ttro/ttxt]

  1. Tabs LDEF
  2.  
  3.  
  4.  
  5. Written by:    Chris White,  Developer Technical Support
  6.     
  7. Copyright:    © 1995 by Apple Computer, Inc. All rights reserved.
  8.  
  9.  
  10.  
  11. What it does
  12.  
  13. "Tabs LDEF" is a custom list definition which allows developers to easily create multiple columned lists using different sizes. While the List Manager does support multiple columns, a problem can occur because each column must be of the same size. We sometimes receive questions from developers asking if it's possible to work around this limitation, because they want to add extra fields to their existing single column lists. Unless you have two or more columns of text all displaying fields of very similar sizes, you can't get a useful display of the fields. Since it's common to have variably sized columns of data with most user interface designs, developers often decide not to add additional information to an existing single column list due to the amount of work involved.  While working around this limitation directly within the current List Manager is not practical, there is another approach developers can take. This LDEF supports tabbed text within a single List Manager column, which allows you to add additional fields or columns to their user interfaces quickly and easily.
  14.  
  15. It also demonstrates:
  16.     -A list definition implementation.
  17.     -A technique to help you debug stand-alone code.
  18.     -An example of how to build a safe fat resource.
  19.     -Use of the new accessor routines which are provided as the first step to being Copland-savvy.
  20.  
  21.  
  22.  
  23. How to use the list definition
  24.  
  25. To use the Tabs LDEF, simply set up an array of 16-bit integers (shorts) that represent the offsets, in points, to each tab column, and assign the address of the array to the list record refCon field. Use embedded tab ('\t') characters within the cell text to force the text to be drawn in the following column. Text that doesn't fit in a single column will be truncated and the ellipse (…) character appended, similar to the Finder's view by Name. The last column's text will be truncated if the text doesn't fit into the list's view.
  26.  
  27.  For example:
  28.  
  29.         static short    theOffsets[] = { 4, 0, 100, 134, 200 };
  30.  
  31.         (*theList)->refCon = (long) &theOffsets;
  32.  
  33. This will display four columns using the positions 0, 100, 134 and 200. That's all you need to do to use the LDEF. A bare bones application is included to demonstrate it.
  34.  
  35.  
  36.  
  37. Limitations and Bugs
  38.  
  39. This is not intended to be a definitive 'document' on how to implement a list definition, but illustrates one approach you can take. Like most projects, this project was implemented under time constraints. There may be better methods available to you depending on your needs and the available time.
  40.  
  41. I'm not aware of any bugs, so if you find any then _please_ let me know.
  42.  
  43.  
  44.  
  45. Building
  46.  
  47. Tabs LDEF has been built under:
  48.     Metrowerks CodeWarrior 7
  49.     Symantec C++ 8.0.1
  50.     Symantec 7.0.4
  51.     MPW E.T.O. #19- 'Latest MPW': Symantec C++ for MPW and MrC.
  52.  
  53. The Symantec environments are using a slightly older version of the Universal Interfaces than MPW and CodeWarrior. Because the source code uses some of the new accessor routines which are provided as the first step to being Copland-savvy, you will need to use a later version of the Universal Interfaces than is provided with the Symantec products, or make some changes to the source code. To change the Universal Interfaces, simply place brackets around the existing folder and place the folder containing the later version into the same folder as the existing ones. The brackets will prevent the development environment from using the files contained within the old folder.
  54.  
  55. The current version of Symantec C++ 8.0 does not allow direct creation of a resource based fragment. Instead, the MPW based tools should be used with the development environment using ToolServer. Since two MPW builds are already included, there is no Symantec C++ 8.0 project for the LDEF itself.
  56.  
  57. The new accessor routines will allow you to remove direct accesses to some of the toolbox data structures, at a source code level. Currently, these accessors are implemented as macros. However, they will be available as true API entry points in Copland.
  58.  
  59. Two MPW make files are included: to build a 68K and a fat version using 'Latest MPW'. The make files have been set up to use Symantec C++ for MPW  (SC) and MrC, together with the interfaces and libraries from 'Latest MPW'.
  60.  
  61.  
  62.  
  63. Strategies
  64.  
  65.  
  66. Error Handling
  67.  
  68. Although there is very little need for error handling in the demonstration application, there are two guidelines that have been used to try and avoid the normal sort of problems that can occur as the result of an error exception. First, each routine cleans up after itself. Second, each routine leaves everything in the same state as it found it in.
  69.  
  70. Having each routine clean up after itself can lead to a number of difficulties in C as far as readability and maintainability are concerned. A block of code dedicated to cleaning up and returning from a routine can be a few lines in length. Duplicating this after each error code leads to inconsistencies, errors, and reduced readability. It's worth using C++ just for the exception handling features, but if you must use C you may want to use a similar approach to this. On occasion, we've used a goto statement to jump to a block of code at the end of the routine. If the clean up code should only be called as the result of an exception, the routine returns before dropping into this clean up code.
  71.  
  72. If the current port or resource file is changed, restore them before leaving the routine. Pay particular attention to this when an error occurs because this is usually the place where it's likely to be overlooked. If a handle needs to be in a particular state, save its current state using the HGetState routine before changing it. The HSetState routine can then be used to restore it, and the problems associated with a routine unintentional changing the state of a handle can be avoided.
  73.  
  74. Runtime errors that should never occur in a bug free program can use a DebugStr call. These can be conditionally compile using a #define. For example, our AddToList routine first validates the ListRef parameter. This routine should always receive a valid ListRef, so we use the following code snippet to prevent the application from crashing, and we can also get an idea of what may have gone wrong. 
  75.  
  76.     #if DEBUGGING
  77.     if ( theList == nil ) DebugStr ( "\p theList == nil");
  78.     #endif
  79.  
  80.  
  81.  
  82. How the Interesting Stuff Works
  83.  
  84.  
  85. Setting up the tab positions
  86.  
  87. As already mentioned, a pointer to an array of 16-bit integers (shorts) is assigned to the list record's refCon field. The first integer is a counter of the number of tab positions used, followed by the values for each tab position. Since the array must be valid while the list is in use, the array will probably need to be allocated as a static or global variable to avoid it going out of scope when the function returns. In this case, I've used a static variable which, hopefully, makes it a little more readable than using a global. Below is a snippet taken from the CreateContentList routine, which can be found in Windows.c.
  88.  
  89.  
  90.     theList = LNew ( &viewRect, &dataRect, cellSize, kLDEFID, theWindow, 
  91.                                                                                 false, false, false, true );
  92.     .
  93.     .
  94.     .
  95.  
  96.     if ( theList )
  97.     {
  98.                 static short    theOffsets[] = { 4, 0, 100, 134, 200 };
  99.         
  100.                 (*theList)->refCon = (long) &theOffsets;
  101.                 (*theList)->selFlags = lOnlyOne;
  102.                 SetWRefCon ( theWindow, (long) theList );
  103.     .
  104.     .
  105.  
  106.  
  107. Debugging stand-alone code
  108.  
  109. Just after the list is created with the LNew toolbox routine, the following code snippet is included:-
  110.  
  111.  
  112.     #ifndef USE_LDEF
  113.         theErr = PatchListLDEF ( theList );
  114.         if ( theErr )
  115.                         return theErr;
  116.     #endif
  117.     
  118.  
  119. This routine sets up the list record's listDefProc field to use the list definition code included in the project itself. With a little modification, this technique can be used to allow source level debugging of most stand-alone code: in this case, the list definition. The current build uses the list definition in the normal way. To switch to using the debugging technique described here, you'll need to comment out a #define in a couple of places and include the list definition source file in the demo application build.
  120.  
  121. It works by allocating a handle and assigning it to the listDefProc field, which is used by the List Manager to store a handle to the LDEF after retrieving it using the Resource Manager. The record we allocate must somehow call the routine which is used as the main entry point of the LDEF. If we're using the Code Fragment Manager (CFM), we take advantage of the Mixed Mode Manager and create a routine descriptor record on the stack, using the BUILD_ROUTINE_DESCRIPTOR macro. The descriptor record is then assigned to the block of memory we allocated as a handle. If the Code Fragment Manager isn't available, we assign a JMP instruction and the address of the LDEF routine. In both cases, when the List Manager checks the listDefProc field and finds that it is non-nil, it calls the code. For CFM, the routine descriptor includes an A-Trap in the first 16-bits which invokes the Mixed Mode Manager. As the descriptor record contains all the information necessary for the Mixed Mode Manager to be able to call the LDEF main entry point, we just let Mixed Mode work its magic in the normal way. For non-CFM, the JMP instruction jumps to the LDEF main entry point. In both cases, the List Manager ends up using the list definition routines which we included directly within the application code. The PatchListLDEF routine can be found in PatchListLDEF.c
  122.  
  123. The demo application currently uses the stand-alone LDEF. If you wish to build the application with the LDEF included directly within the application code, you need to include the Tabs LDEF.c source file and comment out the #define USE_LDEF which can be found in Tabs LDEF.c and BareBones.h. Although the LDEF resource will still be included in the demo application's resource fork, it will not be used.
  124.  
  125.  
  126. Building a safe fat resource
  127.  
  128. For MPW we've included a safe fat build. Develop issue 17 contains an excellent article, “Standalone Code On PowerPC”, which describes this in more detail. Unfortunately, the develop article contained a bug, and although this was fixed on subsequent develop CDs, the tools have also changed a little making it out of date. Further, the terminology seems to have changed slightly, which can cause confusion. What the article describes as a fat resource, is now described as a safe fat resource. Confusingly, a fat resource will _not_ execute on a 68K based Macintosh, but merely contains both PowerPC and 68K code that enables the Mixed Mode Manager to avoid expensive mode switches. A safe fat resource contains both PowerPC and 68K code, and does not rely on the Mixed Mode Manager when only 68K code is required. As a result, a safe fat resource will execute safely on a 68K based Macintosh.
  129.  
  130. The templates defined in MixedMode.r allow creation of both fat resources and safe fat resources,  using the 'fdes' and 'sdes' resource templates, respectively. We're using the 'sdes' template which, unlike a fat resource, will still execute on a 68K based Macintosh. A safe fat resource start with some 68K code which is always executed the first time the resource is called. This code determines if the Mixed Mode Manager is available. If so, a routine descriptor is moved to the beginning of the resource. If not, a branch instruction is placed at the beginning of the resource, which will branch to the 68K code. The next time the resource is called, the correct code will be called immediately. See MixedMode.r for more information.
  131.  
  132. To build a safe fat resource, you need the following Rez definition, which can be found in ldef.r:-
  133.  
  134.     #include "MixedMode.r"
  135.  
  136.     type 'LDEF' as 'sdes';
  137.  
  138.     resource 'LDEF' (1000)
  139.     {
  140.         0x000EBD80,                                // 68K ProcInfo
  141.         0x000EBD80,                                // PowerPC ProcInfo
  142.         $$Resource("LDEF.rsrc", 'oCod', 1000),        // name, type, and ID of rsrc containing 68k code
  143.         $$Resource("LDEF.rsrc", 'pCod', 1000)            // name, type, and ID of rsrc containing ppc code
  144.     };
  145.  
  146.  
  147. It's the job of the makefile to create a single resource which contains the 'sdes' code, the 68K code, and the PowerPC code.
  148.  
  149.     "Tabs LDEF.MPW.FAT"    ƒ LDEF.rsrc
  150.     rez LDEF.r -a -o {Targ}
  151.     setfile -t 'RSRC' -c 'Doug' {Targ}
  152.     .
  153.     .
  154.     .
  155.     LDEF.rsrc ƒƒ {•MondoBuild•} {Objects•68K}
  156.         Link ∂
  157.             -o {Targ} -d {Sym•68K} ∂
  158.             {Objects•68K} ∂
  159.             -t 'RSRC' ∂
  160.             -c 'Doug' ∂
  161.             -rt oCod=1000 ∂
  162.             -m MAIN -sg LDEF
  163.  
  164.  
  165.     LDEF.rsrc ƒƒ {•MondoBuild•} {Objects•PPC}
  166.         PPCLink ∂
  167.             -o LDEF.pef {Sym•PPC} ∂
  168.             {Objects•PPC} ∂
  169.             -t 'RSRC' ∂
  170.             -c 'Doug' ∂
  171.             -m main ∂
  172.             -packData off ∂
  173.             "{SharedLibraries}InterfaceLib" ∂
  174.             "{SharedLibraries}StdCLib" ∂
  175.             "{PPCLibraries}StdCRuntime.o" ∂
  176.             "{PPCLibraries}PPCCRuntime.o"
  177.     echo "read ∂'pCod∂' (1000) ∂"LDEF.pef∂";" | rez -a -o LDEF.rsrc
  178.     .
  179.     .
  180.     .
  181.  
  182. The Rez command is used to pull the fragment out of the data fork, and place it into a resource. The complete makefile can be found at Tabs LDef ƒ:Tabs LDEF.MPW.FAT.make
  183.  
  184. We sometime receive questions from developers who are having problems with native stand-alone code resources. If you have problem with this yourself, double check the ProcInfo information in the Rez file and make sure the PowerPC code has had its data section expanded. These are the two main causes of problems for developers.
  185.  
  186. As you probably know, the ProcInfo field describes the number and size of each parameter, as well as the size of any return result, for the main entry point. It is important to change these values if the number of parameters or the size of the return result changes. If this value is only slightly wrong, serious problems are likely to follow.
  187.  
  188. Normally, the PPCLink tool compresses the data section of the PEF container, which means it does not have space for its global variables. This is fine for applications, but for standalone code resources the data section must not be compressed. The Code Fragment Manager will fail to load and prepare a resource based fragment that was linked in this way, and will return with a -2824 error code. The all important option for the PPCLink tool is -packData off.
  189.  
  190.  
  191.  
  192. Additional functionality to add
  193.  
  194. -Before truncating a string that doesn't fit, use a condensed style to fit more of the original text into the column.
  195. -Support embedded codes within the cell text to control the style of each column's text.
  196.  
  197.  
  198.  
  199. Bugs, Comments and Suggestions
  200.  
  201. Bug reports, comments and suggestions should be made to the AppleLink address DEVSUPPORT and marked for my attention. The level of continued support for this project will largely depend on your feedback. It's my hope to be able to add additional features to this list definition, but without your feedback the features that are important to you may not make it into a future release.
  202.  
  203. Enjoy!
  204.  
  205. Chris White - Dec. '95
  206. © 1995 by Apple Computer, Inc. All rights reserved.
  207.  
  208.